import base64
import json

from decimal import Decimal

import pickle
from django.shortcuts import render
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import View
from django_redis import get_redis_connection

from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from apps.users.models import Address
from django import http

from utils.response_code import RETCODE

"""
订单结算页面的展示需求
    1.这个界面必须是登录用户
    2.获取用户信息
    3.根据用户信息，获取地址信息
    4.连接redis，获取redis中的 hash和set数据
    5.将bytes数据类型进行转换，转换的同时我们重新组织选中的商品数据
    6.获取商品的id，根据商品id查询商品信息[sku,sku]
    7.对商品列表进行遍历
    8.遍历的过程中，对sku添加数量和对应商品的总金额
        也去计算当前订单的总数量和总金额
"""


# 结算订单
class PlaceOrederView(LoginRequiredMixin, View):
    def get(self, request):
        # 1.这个界面必须是登录用户
        # 2.获取用户信息
        user = request.user
        # 3.根据用户信息，获取地址信息
        try:
            addresses = Address.objects.filter(user=user, is_deleted=False)
        except Exception as e:
            return http.HttpResponseBadRequest("未找到数据！")
        # 4.连接redis，获取redis中的 hash和set数据
        redis_conn = get_redis_connection("carts")
        sku_id_count = redis_conn.hgetall("carts_%s" % user.id)
        ids = redis_conn.smembers("selected_%s" % user.id)
        # 5.将bytes数据类型进行转换，转换的同时我们重新组织选中的商品数据
        selected_carts = {}

        for id in ids:
            selected_carts[int(id)] = int(sku_id_count[id])
        # 6.获取商品的id，根据商品id查询商品信息[sku,sku]

        ids = selected_carts.keys()
        skus = SKU.objects.filter(pk__in=ids)
        # 7.对商品列表进行遍历
        total_count = 0
        from  decimal import Decimal
        total_amount = Decimal('0')
        for sku in skus:
            # 8.遍历的过程中，对sku添加数量和对应商品的总金额
            sku.count = selected_carts[sku.id]  # 数量小计
            sku.amount = sku.count * sku.price  # 金额小计
            # 也去计算当前订单的总数量和总金额
            total_count += sku.count
            total_amount += sku.amount

        # 在添加一个运费信息
        freight = Decimal('10.00')

        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount + freight
        }
        return render(request, 'place_order.html', context=context)

        #     也去计算当前订单的总数量和总金额


# 生成订单
class OrderCommitView(LoginRequiredMixin, View):
    """
    生成订单信息需要涉及到订单基本信息和订单商品信息
    订单基本信息和订单商品信息是一对多的关系
    所以 先生成订单基本信息  再生成订单商品信息
    1. 生成订单基本信息
        1.1 必须是登录用户才可以访问，获取用户信息
        1.2 获取提交的地址信息
        1.3 获取提交的支付方式
        1.4 手动生成一个订单id，年月日时分秒 +9位用户id
        1.5 运费，总金额和总数量(初始化为0)
        1.6 订单状态(有支付方式决定)
    2. 生成订单商品信息
        2.1 连接redis，获取redis中的数据
        2.2 获取选中的商品id[1,2,3]
        2.3 对id进行遍历
        2.4 查询商品
        2.5 库存量的判断
        2.6 修改商品的库存和销量
        2.7 累加总数量和总金额
        2.8 保存订单商品信息
        2.9 保存订单的总数量和总金额
    """

    def post(self, request):
        # 1. 生成订单基本信息
        #     1.1 必须是登录用户才可以访问，获取用户信息
        user = request.user
        #     1.2 获取提交的地址信息
        data = json.loads(request.body.decode())
        address_id = data.get("address_id")
        try:
            address = Address.objects.get(pk=address_id)
        except Address.DoesNotExist:
            return http.JsonResponse({"code": RETCODE, "errmsg": "参数错误！"})
        # 1.3 获取提交的支付方式
        pay_method = data.get("pay_method")
        # 判断支付方式
        if not pay_method in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.JsonResponse({"code": RETCODE.PARAMERR, "errmsg": "参数错误！"})
            #     1.4 手动生成一个订单id，年月日时分秒 +9位用户id
        from django.utils import timezone
        order_id = timezone.now().strftime('%Y%m%d%H%M%S') + '%09d' % user.id
        #     1.5 运费，总金额和总数量(初始化为0)
        freight = Decimal('10.00')  # 运费
        total_amount = Decimal('0')  # 总金额
        total_count = 0
        #     1.6 订单状态(有支付方式决定)
        if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH']:
            status = OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        else:
            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID']
        # 创建事务
        from django.db import transaction
        with transaction.atomic():
            # 事务回滚的点
            save_point = transaction.savepoint()
            order = OrderInfo.objects.create(
                order_id=order_id,
                user=user,
                address=address,
                total_amount=total_amount,
                total_count=total_count,
                freight=freight,
                pay_method=pay_method,
                status=status
            )
            # 2. 生成订单商品信息
            #     2.1 连接redis，获取redis中的数据
            redis_conn = get_redis_connection("carts")
            id_count = redis_conn.hgetall('carts_%s' % user.id)
            selected_ids = redis_conn.smembers('selected_%s' % user.id)

            selected_carts = {}
            for id in selected_ids:
                selected_carts[int(id)] = int(id_count[id])
            # 2.2 获取选中的商品id[1,2,3]
            ids = selected_carts.keys()
            #     2.3 对id进行遍历
            for id in ids:
                #     2.4 查询商品
                sku = SKU.objects.get(pk=id)
                #     2.5 库存量的判断
                count = selected_carts[sku.id]
                if sku.stock < count:
                    # 说明不足
                    return http.JsonResponse({"code": RETCODE.STOCKERR, "errmsg": "库存不足！"})
                # 2.6 修改商品的库存和销量
                # sku.stock -= count
                # sku.sales += count
                # sku.save()

                # 乐观锁
                # 先获取之前的库存
                old_stock = sku.stock
                # 新库存和新销量
                new_stock = sku.stock - count
                new_sales = sku.sales + count

                rect = SKU.objects.filter(id=id, stock=old_stock).update(
                    stock=new_stock,
                    sales=new_sales
                )
                if rect == 0:
                    # 事务回复
                    transaction.savepoint_rollback(save_point)
                    raise Exception('下单失败')
                # 2.7 累加总数量和总金额
                order.total_count += count
                order.total_amount += (sku.price * count)
                #     2.8 保存订单商品信息
                OrderGoods.objects.create(
                    order=order,
                    sku=sku,
                    count=count,
                    price=sku.price
                )
            # 2.9 保存订单的总数量和总金额
            order.save()

            # 事务提交
            transaction.savepoint_commit(save_point)

            # 3. 删除redis中选中的商品信息

        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "ok", "order_id": order.order_id})

    def delete(self, request):
        """
        1.接受数据(sku_id)
        2.验证数据(验证商品是否存在)
        3.获取用户信息
        4.登录用户操作redis
            4.1 连接redis
            4.2 删除数据
            4.3 返回响应
        5.未登录用户操作cookie
            5.1 获取cookie信息
            5.2 判断数据是否存在
            5.3 删除数据
            5.4 对最新的数据进行加密处理
            5.5 返回响应
        """
        # 1.接受数据(sku_id)
        data = json.loads(request.body.decode())
        sku_id = data.get("sku_id")
        # 2.验证数据(验证商品是否存在)
        try:
            sku = SKU.objects.get(pk=sku_id)
        except SKU.DoesNotExist:
            return http.JsonResponse({"code": RETCODE.NODATAERR, "errmsg": "没有数据"})
        # 3.获取用户信息
        user = request.user
        if user.is_authenticated:
            # 4.登录用户操作redis
            #     4.1 连接redis
            redis_conn = get_redis_connection("carts")
            #     4.2 删除数据
            # redis_conn.hdel("carts_%s"%user.id,sku_id)
            # redis_conn.srem("carts_%s"%user.id,sku_id)
            pl = redis_conn.pipeline()
            # 删除键，就等价于删除了整条记录
            pl.hdel('carts_%s' % user.id, sku_id)
            pl.srem('selected_%s' % user.id, sku_id)
            pl.execute()
            #     4.3 返回响应
            return http.JsonResponse({"code": RETCODE.OK, "errmsg": "ok"})
        else:
            # 5.未登录用户操作cookie
            #     5.1 获取cookie信息
            carts = request.COOKIES.get("carts")
            #     5.2 判断数据是否存在
            if carts is not None:
                cookie_cart = pickle.loads(base64.b64decode(carts))
            else:
                cookie_cart = {}
            # 5.3 删除数据
            if sku_id in cookie_cart:
                del cookie_cart[sku_id]
            # 5.4 对最新的数据进行加密处理
            cookie_data = base64.b64encode(pickle.dumps(cookie_cart))
            #     5.5 返回响应
            response = http.JsonResponse({"code": RETCODE.OK, "errmsg": "ok"})
            response.set_cookie("carts", cookie_data, 3600)
            return response


# 结算成功展示
class OrderSuccessView(LoginRequiredMixin, View):
    def get(self, request):
        order_id = request.GET.get("order_id")
        payment_amount = request.GET.get("payment_amount")
        pay_method = request.GET.get("pay_method")

        context = {
            "order_id": order_id,
            "payment_amount": payment_amount,
            "pay_method": pay_method
        }

        return render(request, 'order_success.html', context=context)
